//
// CVideoDevices.cpp
//

/*-----------------------------------------------------*\
			HQ Tech, Make Technology Easy!       
 More information, please go to http://hqtech.nease.net.
/*-----------------------------------------------------*/

#include "stdafx.h"
#include <streams.h>
#include "CVideoDevices.h"
#include "UDsUtils.h"
#include "CDeviceObserver.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CVideoDevices * CVideoDevices::sDevices = NULL;
/////////////////////////////////////////////////////////////////////////
CVideoDevices::CVideoDevices()
{
	mWindow  = new CDeviceObserver();
	mWindow->AddMsgReceiver(this);
	mWindow->Create(0, "Devices", WS_POPUPWINDOW, CRect(0, 0, 2, 2), 0, 0);

	Populate();
}

CVideoDevices::~CVideoDevices()
{
	mWindow->DestroyWindow();
	mList.RemoveAll();
}

CVideoDevices * CVideoDevices::Instance(void)
{
	if (sDevices == NULL)
	{
		sDevices = new CVideoDevices();
	}
	return sDevices;
}

void CVideoDevices::Release(void)
{
	if (sDevices)
	{
		delete sDevices;
		sDevices = NULL;
	}
}

void CVideoDevices::Populate(void)
{
	mList.RemoveAll();
	UDsUtils::QueryVideoCaptureDevices(mList);
}

BOOL CVideoDevices::FindDevice(const char * inDeviceName, 
							   CDSDevice& outDevice)
{
	POSITION pos = mList.GetHeadPosition();
	while (pos)
	{
		CDSDevice device = mList.GetNext(pos);
		if (device.GetDeviceFriendlyName().Compare(inDeviceName) == 0)
		{
			outDevice = device;
			return TRUE;
		}
	}
	return FALSE;
}

// Given the display name of the device
BOOL CVideoDevices::AddDevice(const char * inDeviceName)
{
	char friendlyName[1024];
	IBaseFilter * pFilter = UDsUtils::CreateDevice(TRUE, 
		inDeviceName, friendlyName);
	if (pFilter)
	{
		CDSDevice device;
		device.SetDeviceDisplayName(inDeviceName);
		device.SetDeviceFriendlyName(friendlyName);
		device.SetDevideType(UDsUtils::DecideDeviceType(pFilter));
		mList.AddTail(device);

		pFilter->Release();
		return TRUE;
	}
	return FALSE;
}

// Given the display name of the device
void CVideoDevices::RemoveDevice(const char * inDeviceName)
{
	POSITION pos = mList.GetHeadPosition();
	POSITION previousPos;
	while (pos)
	{
		previousPos = pos;   // Save for later use

		CDSDevice device = mList.GetNext(pos);
		if (UDsUtils::IsSameDevice(device.GetDeviceDisplayName(), inDeviceName))
		{
			mList.RemoveAt(previousPos);
			break;
		}
	}
}

bool CVideoDevices::ReceiveMessage(MessageT inMessage, 
								   void * ioParam,
								   void * ioParam2)
{
	BOOL pass = TRUE;

	switch (inMessage)
	{
	case msg_PnPDeviceAdded:
		pass = AddDevice((const char *)ioParam);
		break;

	case msg_PnPDeviceRemoved:
		// Wait for DirectShow processing...
		Sleep(100);
		RemoveDevice((const char *) ioParam);
		break;
	}

	if (pass)
	{
		// Broadcast to the upper receiver to do sth. else
		return Broadcast(inMessage, ioParam, ioParam2);
	}
	return true;
}